﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Common;

using CSGame.DispatcherService;
using System.Threading;
using System.Net.Sockets;
using System.Net;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;

namespace CSGame
{
	public delegate void StepEventHandler(ChessStep step);

    public partial class frmClient : Form
    {
        private bool _local = true; // играем ли мы локально или глобально
		private GameInfo _gameInfo;

		Thread _listenerThread;
		TcpListener _listener;

		ClientTerminal _terminal;

		StepEventHandler _handler;

		bool _gameActive;

		bool _forceSendMsg;

        public frmClient()
        {
            InitializeComponent();
            chessBox1.StartPosition();
			
        }

		public frmClient(GameInfo gameInfo)
		{
			InitializeComponent();
			chessBox1.StartPosition();
			
			_local = false;
			_gameInfo = gameInfo;
			this._handler = new StepEventHandler(MakeStep);
			chessBox1.PlaingBy = _gameInfo.PlayerType;
			if (_gameInfo.PlayerType == Player.Black)
				this.chessBox1.SeeBy(Player.Black);
			lblPlay.Text = Resources.FigureColour + " : " + (this.chessBox1.PlaingBy == Player.White ?
				Resources.ColourWhite : Resources.ColourBlack);
			lblWho.Text = Resources.WhoTurn + " : " + (this.chessBox1.StepBy == Player.White ?
				Resources.ColourWhite : Resources.ColourBlack);
			_gameActive = true;
			_forceSendMsg = true;
			
		}

		void _terminal_MessageRecived(Socket socket, byte[] buffer)
		{
			if (!_gameActive)
				return;

			MemoryStream stream = new MemoryStream(buffer);
			BinaryFormatter formatter = new BinaryFormatter();
			ServerMessage msg = formatter.Deserialize(stream) as ServerMessage;

			switch (msg.Type)
			{
				case ServerMessageType.PlayerTurn:
					PlayerTurnServerMessage playerMsg = msg as PlayerTurnServerMessage;
					if (playerMsg.GameId == _gameInfo.GameId)
						//this.chessBox1.DoStep(playerMsg.Step.Start, playerMsg.Step.Finish);
						this.Invoke(this._handler, new object[] { playerMsg.Step });
					break;
				case ServerMessageType.PlayerLost:
					PlayerLostServerMessage lostMsg = msg as PlayerLostServerMessage;
					if (lostMsg.GameId == _gameInfo.GameId)
					{
						if (lostMsg.UserName == _gameInfo.PlayerName)
							MessageBox.Show(Resources.Defeat);
						else MessageBox.Show(Resources.Victory);
						_gameActive = false;
						this.Close();
					}
					break;
			}
		}

		private void MakeStep(ChessStep step)
		{
			this.chessBox1.DoStep(step);
			lblPlay.Text = Resources.FigureColour + " : " + (this.chessBox1.PlaingBy == Player.White ?
				Resources.ColourWhite : Resources.ColourBlack);
			lblWho.Text = Resources.WhoTurn + " : " + (this.chessBox1.StepBy == Player.White ?
				Resources.ColourWhite : Resources.ColourBlack);
		}

		void _terminal_Disconncted(Socket socket)
		{
			//throw new NotImplementedException();
		}

		void _terminal_Connected(Socket socket)
		{
			//throw new NotImplementedException();
		}

        private void перевернутьToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (chessBox1.ViewBy == Player.White)
                chessBox1.SeeBy(Player.Black);
            else
                chessBox1.SeeBy(Player.White);
        }

        /// <summary>
        /// Перед ходом
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void chessBox1_BeforeChessGo(object sender, ChessBeforeStepEventArgs e)
        {
			if (_local)
			{ // ходит другой чел
				if (chessBox1.StepBy == Player.White)
					chessBox1.SeeBy(Player.Black);
				else
					chessBox1.SeeBy(Player.White);
				chessBox1.PlaingBy = chessBox1.ViewBy;
			}
			else
			{
				PlayerTurnServerMessage msg = new PlayerTurnServerMessage(e.Step, _gameInfo.GameId);
				SendMessage(msg);
			}
        }

        private void локальноСЧеловекомToolStripMenuItem_Click(object sender, EventArgs e)
        {
            chessBox1.StartPosition(); // новая игра
            chessBox1.PlaingBy = Player.White;
        }

		private void новаяИграToolStripMenuItem_Click(object sender, EventArgs e)
		{

		}

		private void frmClient_FormClosing(object sender, FormClosingEventArgs e)
		{
			if (!_local && _forceSendMsg)
			{
				PlayerLostServerMessage msg = new PlayerLostServerMessage(_gameInfo.PlayerName, _gameInfo.GameId);
				SendMessage(msg);
			}
		}

		private void frmClient_Shown(object sender, EventArgs e)
		{
			if (!_local)
			{
				try
				{
					_terminal = new ClientTerminal();

					_terminal.Connected += new TCPTerminal_ConnectDel(_terminal_Connected);
					_terminal.Disconncted += new TCPTerminal_DisconnectDel(_terminal_Disconncted);
					_terminal.MessageRecived += new TCPTerminal_MessageRecivedDel(_terminal_MessageRecived);

					_terminal.Connect(IPAddress.Parse(_gameInfo.GameAddress), 12345);

					_terminal.StartListen();
				}
				catch (Exception ex)
				{
					MessageBox.Show(Resources.AppClosing, Resources.ErrorMsgCaption);
					_forceSendMsg = false;
					this.Close();
				}
			}
		}

		private void сдатьсяToolStripMenuItem_Click(object sender, EventArgs e)
		{
			if (!_local)
			{
				PlayerLostServerMessage msg = new PlayerLostServerMessage(_gameInfo.PlayerName, _gameInfo.GameId);
				SendMessage(msg);
			}
		}

		private void SendMessage(ServerMessage msg)
		{
			try
			{
				BinaryFormatter formatter = new BinaryFormatter();
				MemoryStream stream = new MemoryStream();
				formatter.Serialize(stream, msg);
				byte[] buffer = stream.ToArray();
				_terminal.SendMessage(buffer);
			}
			catch (Exception ex)
			{
				MessageBox.Show(Resources.AppClosing, Resources.ErrorMsgCaption);
				_forceSendMsg = false;
				this.Close();
			}
		}

		private void chessBox1_AfterChessGo(object sender, ChessAfterStepEventArgs e)
		{
			if (e.Danger && this.chessBox1.PlaingBy == this.chessBox1.StepBy)
				MessageBox.Show(Resources.Check);
		}
    }
}
